#include "tcp_server.h"
#include <vector>
#include <string>

namespace	STLF{

void request_handler::handle_request(const BUFFER& buf, connection_ptr session_ptr)
{

		log() << buf.data() <<endl;

		session_ptr->write("nihao", 100);

		session_ptr->disconnect_safty();

/*		
		char bf[100000];
		memset(bf, 0, 100000);
		
		memset(bf, 31, 100000-1);

		session_ptr->async_send(bf, 100000);
		session_ptr->disconnect_safty();
*/

}

//////////////////////////////////////////////////////////////////////////
connection::connection(boost::asio::io_service& io_service,
					   connection_manager& manager, request_handler& handler)
					   : socket_(io_service),_io_service(io_service),_need_disconnect(false),
					   connection_manager_(manager),
					   request_handler_(handler)
{
	memset(buffer_.data(), 0, buffer_.size());
}

boost::asio::ip::tcp::socket& connection::socket()
{
	return socket_;
}

void connection::_start()
{
	socket_.async_read_some(boost::asio::buffer(buffer_),
		boost::bind(&connection::handle_read, shared_from_this(),
		boost::asio::placeholders::error,
		boost::asio::placeholders::bytes_transferred));
}

#define DISCONNECT_LOGGING	\
boost::asio::ip::tcp::socket::endpoint_type et = socket_.remote_endpoint();\
log() << "client["<<et.address() <<":" << et.port() <<"] disconnected"<< endl;


void connection::_stop()
{
	DISCONNECT_LOGGING

	socket_.close();
}

void connection::async_write(char *p, int num)
{
	boost::asio::async_write(socket_, boost::asio::buffer(p, num),
		boost::bind(&connection::handle_write, shared_from_this(),
		boost::asio::placeholders::error));
}

void connection::write(char *p, int num)
{
	boost::system::error_code ignored_error;
	boost::asio::write(socket_, boost::asio::buffer(p, num),
		boost::asio::transfer_all(), ignored_error);
}

void connection::disconnect_safty()
{
	_need_disconnect = true;
}

void connection::handle_read(const boost::system::error_code& e,
							 std::size_t bytes_transferred)
{
	if (!e)
	{
		if (_need_disconnect)
		{	
			boost::system::error_code ignored_ec;
			socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
		}
		else
		{

			request_handler_.handle_request(buffer_, shared_from_this());

			socket_.async_read_some(boost::asio::buffer(buffer_),
				boost::bind(&connection::handle_read, 
				shared_from_this(),
				boost::asio::placeholders::error,
				boost::asio::placeholders::bytes_transferred));
		}
	}
	else if (e != boost::asio::error::operation_aborted)
	{
		connection_manager_.stop(shared_from_this());
	}
}

void connection::handle_write(const boost::system::error_code& e)
{
	if (!e)
	{
		// Initiate graceful connection closure.
		if (_need_disconnect)
		{	
			boost::system::error_code ignored_ec;
			socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec);
		}

	}
	else if (e != boost::asio::error::operation_aborted)
	{
		connection_manager_.stop(shared_from_this());
	}
}

//////////////////////////////////////////////////////////////////////////
void connection_manager::start(connection_ptr c)
{
	connections_.insert(c);
	c->_start();
}

void connection_manager::stop(connection_ptr c)
{
	connections_.erase(c);
	c->_stop();
}

void connection_manager::stop_all()
{
	std::for_each(connections_.begin(), connections_.end(),
		boost::bind(&connection::_stop, _1));
	connections_.clear();
}

//////////////////////////////////////////////////////////////////////////

tcp_server::tcp_server(const std::string& address, const std::string& port,
			   request_handler& user_request_handler )
			   : io_service_(),
			   acceptor_(io_service_),
			   connection_manager_(),
			   new_connection_(new connection(io_service_,
			   connection_manager_, request_handler_)),
			   request_handler_( user_request_handler)
{
	// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
	boost::asio::ip::tcp::resolver resolver(io_service_);
	boost::asio::ip::tcp::resolver::query query(address, port);
	boost::asio::ip::tcp::endpoint endpoint = *resolver.resolve(query);
	acceptor_.open(endpoint.protocol());
	acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
	acceptor_.bind(endpoint);
	acceptor_.listen();
	acceptor_.async_accept(new_connection_->socket(),
		boost::bind(&tcp_server::handle_accept, this,
		boost::asio::placeholders::error));
}

void tcp_server::run()
{
	// The io_service::run() call will block until all asynchronous operations
	// have finished. While the tcp_server is running, there is always at least one
	// asynchronous operation outstanding: the asynchronous accept call waiting
	// for new incoming connections.
	io_service_.run();
}

void tcp_server::stop()
{
	// Post a call to the _stop function so that tcp_server::_stop() is safe to call
	// from any thread.
	io_service_.post(boost::bind(&tcp_server::handle_stop, this));
}

#define CONNECT_LOGGING   \
boost::asio::ip::tcp::socket &cs = new_connection_->socket(); \
boost::asio::ip::tcp::socket::endpoint_type et = cs.remote_endpoint(); \
log() << "accepted a new client[" << et.address() << ":" <<et.port() <<"]"<< endl;

void tcp_server::handle_accept(const boost::system::error_code& e)
{
	if (!e)
	{
		connection_manager_.start(new_connection_);

		CONNECT_LOGGING

		new_connection_.reset(new connection(io_service_,
			connection_manager_, request_handler_));
		acceptor_.async_accept(new_connection_->socket(),
			boost::bind(&tcp_server::handle_accept, this,
			boost::asio::placeholders::error));
	}
}

void tcp_server::handle_stop()
{
	// The tcp_server is stopped by cancelling all outstanding asynchronous
	// operations. Once all operations have finished the io_service::run() call
	// will exit.
	acceptor_.close();
	connection_manager_.stop_all();
}


}